#include "tcommandexecprocess.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonParseError>
#include <QFile>
#include <QThread>
#include <QDebug>
#include <QFileInfo>
#include <QDir>

TCommandExecProcess::TCommandExecProcess(QObject *parent)
    : QObject(parent),m_commandIndex(0),m_sshConnection(nullptr),m_shellReady(false),m_sftpReady(false),m_upDatFinish(false)
{
}

TCommandExecProcess::~TCommandExecProcess()
{
    if(m_sshConnection) {
        m_sshConnection->disconnectFromHost();
    }
}

/**
 * @brief 设置参数
 * @param configFilePath 升级文件信息
 * @param devIP          设备IP
 */
void TCommandExecProcess::setConfig(const QString &configFilePath, const QString &devIP)
{
    m_configFilePath = configFilePath;
    m_devIP = devIP;
}

/**
 * @brief 从文件中加载
 * @param filePath 文件路径
 */
void TCommandExecProcess::loadFromFile(const QString &filePath)
{
    QFile configFile;
    configFile.setFileName(filePath);
    configFile.open(QFile::ReadOnly);
    QByteArray configData = configFile.readAll();
    configFile.close();

    m_commandUnitList.clear();
    QJsonDocument njsondoc = QJsonDocument::fromJson(configData);
    if(!njsondoc.isNull()) {
        if(njsondoc.isObject()) {
            QJsonObject njsonbj_root = njsondoc.object();
            //校验命令
            QString cmdType = njsonbj_root.value("CmdType").toString();
            //校验通过
            if(cmdType == CMD_TYPE_CHECK) {
                //指令
                QJsonValue njsonval_commands = njsonbj_root.value("Commands");
                if(njsonval_commands.isArray()) {
                    QJsonArray njsonarr_commands = njsonval_commands.toArray();
                    for(int i=0;i<njsonarr_commands.size();i++) {
                        QJsonObject njsonobj_command = njsonarr_commands.at(i).toObject();
                        TCommandUnit commandUnit;
                        commandUnit.Type = njsonobj_command.value("Type").toString();
                        commandUnit.Command = njsonobj_command.value("Command").toString();
                        commandUnit.FileSrcPath = njsonobj_command.value("FileSrcPath").toString();
                        commandUnit.FileDstPath = njsonobj_command.value("FileDstPath").toString();
                        m_commandUnitList.append(commandUnit);
                     }
                }
            }
        }
    }
}

/**
 * @brief 连接设备
 * @param ipAddr 设备IP地址
 */
void TCommandExecProcess::connectDevice(const QString &ipAddr)
{
    m_sshParams.setHost(ipAddr);
    m_sshParams.setUserName("root");
    m_sshParams.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword;
    m_sshParams.setPassword("lrtech");
    m_sshParams.setPort(22);
    m_sshParams.timeout = 10;

    if(!m_sshConnection) {
        m_sshConnection = new QSsh::SshConnection(m_sshParams);
        connect(m_sshConnection,&QSsh::SshConnection::connected,this,&TCommandExecProcess::slotSshConnected);
        connect(m_sshConnection,&QSsh::SshConnection::disconnected,this,&TCommandExecProcess::slotSshDisconnected);
        connect(m_sshConnection,&QSsh::SshConnection::error,this,&TCommandExecProcess::slotSshError);
        m_sshConnection->connectToHost();
    }
}

/**
 * @brief 执行指令
 */
void TCommandExecProcess::executeCommand()
{
    if(m_shellReady && m_sftpReady) {
        //正常执行指令
        if(m_commandIndex >= 0 && m_commandIndex < m_commandUnitList.size()) {
            TCommandUnit commandUnit = m_commandUnitList.at(m_commandIndex);
            //指令
            if(commandUnit.Type == CMD_TYPE_PLAIN_COMMAND) {
                QString command = commandUnit.Command + "\n";
                m_sshShell->write(command.toUtf8());
                m_commandReply.clear();
                qDebug() << "执行指令" << command;
            }
            //文件
            else if(commandUnit.Type == CMD_TYPE_UPLOAD_FILE) {
                QSsh::SftpJobId job = m_sftpChannel->uploadFile(QFileInfo(m_configFilePath).dir().path() + "\\" + commandUnit.FileSrcPath,commandUnit.FileDstPath,QSsh::SftpOverwriteExisting);
                if(job != QSsh::SftpInvalidJob) {
                    qDebug() << "上传文件";
                }
                else {
                    m_sshConnection->disconnectFromHost();
                }
            }
            m_commandIndex += 1;
        }
        //指令执行完成
        else if(m_commandIndex == m_commandUnitList.size()) {
            m_upDatFinish = true;
            m_sshConnection->disconnectFromHost();
        }
    }
}

/**
 * @brief 开始升级
 */
void TCommandExecProcess::slotStartUpDat()
{
    loadFromFile(m_configFilePath);
    m_shellReady = false;
    m_sftpReady = false;
    m_commandIndex = -1;
    connectDevice(m_devIP);
}

/**
 * @brief ssh连接建立
 */
void TCommandExecProcess::slotSshConnected()
{
    qDebug() << "ssh连接";

    m_sshShell = m_sshConnection->createRemoteShell();
    connect(m_sshShell.data(),&QSsh::SshRemoteProcess::started,this,&TCommandExecProcess::slotSshShellStarted);
    connect(m_sshShell.data(),&QSsh::SshRemoteProcess::closed,this,&TCommandExecProcess::slotSshShellClosed);
    connect(m_sshShell.data(),&QSsh::SshRemoteProcess::readyReadStandardOutput,this,&TCommandExecProcess::slotSshShellReadyReadStandardOutput);
    connect(m_sshShell.data(),&QSsh::SshRemoteProcess::readyReadStandardError,this,&TCommandExecProcess::slotSshShellReadyReadStandardError);
    m_sshShell->start();

    m_sftpChannel = m_sshConnection->createSftpChannel();
    connect(m_sftpChannel.data(),&QSsh::SftpChannel::initialized,this,&TCommandExecProcess::slotSftpInitialized);
    connect(m_sftpChannel.data(),&QSsh::SftpChannel::finished,this,&TCommandExecProcess::slotSftpFinished);
    connect(m_sftpChannel.data(),&QSsh::SftpChannel::closed,this,&TCommandExecProcess::slotSftpClosed);
    m_sftpChannel->initialize();

    emit sigUpdatMessage(LRWM_UPDATPLUGIN_CONNECTOK,false);
}

/**
 * @brief ssh断开连接
 */
void TCommandExecProcess::slotSshDisconnected()
{
    qDebug() << "ssh断开连接";

    delete m_sshConnection;
    m_sshConnection = nullptr;
    if(m_upDatFinish) {
        emit sigUpdatMessage(LRWM_UPDATPLUGIN_FINISH,true);
    }
    else {
        emit sigUpdatMessage(LRWM_UPDATPLUGIN_FAIL,true);
    }
}

/**
 * @brief TCommandExecProcess::slotSshError
 * @param error
 */
void TCommandExecProcess::slotSshError(QSsh::SshError error)
{
    qDebug() << "ssh错误" << error;
    delete m_sshConnection;
    m_sshConnection = nullptr;
    emit sigUpdatMessage(LRWM_UPDATPLUGIN_FAIL,true);
}

/**
 * @brief ssh shell启动
 */
void TCommandExecProcess::slotSshShellStarted()
{
    qDebug() << "shell启动";
    m_shellReady = true;
}

/**
 * @brief ssh shell收到数据
 */
void TCommandExecProcess::slotSshShellReadyReadStandardOutput()
{
    QByteArray readData = m_sshShell->readAllStandardOutput();
    m_commandReply.append(readData);
    if(m_commandReply.endsWith("# ")) {
        emit sigShowLog(m_commandReply);
        m_commandReply.clear();
        //此时指令执行还没有开始 这是第一条指令
        if(m_commandIndex == -1) {
            m_commandIndex = 0;
        }
        executeCommand();
    }
}

/**
 * @brief ssh shell收到错误数据
 */
void TCommandExecProcess::slotSshShellReadyReadStandardError()
{
    QByteArray readErrorData = m_sshShell->readAllStandardError();
    qDebug() << "shell error:" << readErrorData;
}

/**
 * @brief ssh shell关闭
 */
void TCommandExecProcess::slotSshShellClosed()
{
    qDebug() << "shell关闭";
}

/**
 * @brief Sftp初始化
 */
void TCommandExecProcess::slotSftpInitialized()
{
    qDebug() << "sftp初始化";
    m_sftpReady = true;
    executeCommand();
}

/**
 * @brief Sftp关闭
 */
void TCommandExecProcess::slotSftpClosed()
{
    qDebug() << "sftp关闭";
}

/**
 * @brief Sftp完成
 */
void TCommandExecProcess::slotSftpFinished(QSsh::SftpJobId job,const QString &error)
{
    qDebug() << "sftp完成" << job << error;
    //文件上传成功
    if(error.isEmpty()) {
        executeCommand();
    }
    //文件上传失败
    else {
        m_sshConnection->disconnectFromHost();
    }
}

